package com.ruoyi.system.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;

public class FileToolUtil extends FileUtil {

    private static final Logger logger = LoggerFactory.getLogger(FileToolUtil.class);

    /**
     * MultipartFile转File
     */
    public static File toFile(MultipartFile multipartFile)
    {
        // 获取文件名
        String fileName = multipartFile.getOriginalFilename();
        // 获取文件后缀
        String prefix = "." + getExtensionName(fileName);
        File file = null;
        try
        {
            // 用uuid作为文件名，防止生成的临时文件重复
            file = new File(FileUtils.getTempDirectory() + File.separator + IdUtil.simpleUUID() + prefix);
            // MultipartFile to File
            multipartFile.transferTo(file);
        }
        catch (IOException e)
        {
            logger.error(e.getMessage(), e);
        }
        return file;
    }

    /**
     * 获取文件扩展名，不带 .
     */
    public static String getExtensionName(String filename)
    {
        if ((filename != null) && (filename.length() > 0))
        {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length() - 1)))
            {
                return filename.substring(dot + 1);
            }
        }
        return filename;
    }

    /**
     * Java文件操作 获取不带扩展名的文件名
     */
    public static String getFileNameNoEx(String filename)
    {
        if ((filename != null) && (filename.length() > 0))
        {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length())))
            {
                return filename.substring(0, dot);
            }
        }
        return filename;
    }


    /**
     * inputStream 转 File
     */
    static File inputStreamToFile(InputStream ins, String name)
    {
        File file = new File(FileUtils.getTempDirectory() + File.separator + name);
        if (file.exists())
        {
            return file;
        }
        OutputStream os = null;
        try
        {
            os = new FileOutputStream(file);
            int bytesRead;
            int len = 8192;
            byte[] buffer = new byte[len];
            while ((bytesRead = ins.read(buffer, 0, len)) != -1)
            {
                os.write(buffer, 0, bytesRead);
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            IOUtils.closeQuietly(os);
            IOUtils.closeQuietly(ins);
        }
        return file;
    }

    /**
     * @Description: file 转 MultipartFile
     * @param file
     * @return: MultipartFile
     */
    public static MultipartFile fileToMultipartFile(File file)
    {
        FileInputStream fileInputStream = null;
        MultipartFile multipartFile = null;
        try
        {
            fileInputStream = new FileInputStream(file);
            multipartFile = new MockMultipartFile(file.getName(), file.getName(), ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return multipartFile;
    }

    /**
     * 递归获取指定文件夹下所有文件，不含文件夹
     * @param dirFilePath 文件夹路径
     * @param rejectFileNames 过滤掉的文件
     * @return List<File>
     */
    public static List<File> getAllFile(String dirFilePath, List<String> rejectFileNames)
    {
        if (StringUtils.isEmpty(dirFilePath))
        {
            return null;
        }
        return getAllFile(new File(dirFilePath), rejectFileNames);
    }

    /**
     * 递归获取指定文件夹下所有文件
     * @param dirFile 文件
     * @param rejectFileNames 过滤掉的文件
     * @return List<File>
     */
    public static List<File> getAllFile(File dirFile, List<String> rejectFileNames)
    {
        // 如果文件夹不存在或着不是文件夹，则返回 null
        if (Objects.isNull(dirFile) || !dirFile.exists() || dirFile.isFile())
        {
            return null;
        }
        File[] childrenFiles = dirFile.listFiles();
        if (Objects.isNull(childrenFiles) || childrenFiles.length == 0)
        {
            return null;
        }
        List<File> files = new ArrayList<>();
        for (File childFile : childrenFiles)
        {
            // 如果是文件，直接添加到结果集合
            if (childFile.isFile() && !rejectFileNames.contains(childFile.getName()))
            {
                files.add(childFile);
            }
            else
            {
                // 如果是文件夹，则将其内部文件添加进结果集合
                List<File> cFiles = getAllFile(childFile, rejectFileNames);
                if (Objects.isNull(cFiles) || cFiles.isEmpty()) {continue;}
                files.addAll(cFiles);
            }
        }
        return files;
    }

    /**
     * 将压缩文件中指定后缀名称的文件解压到指定目录
     * @param compressFile 压缩文件
     * @param baseDirectory 解压到的基础目录（在此目录下创建UUID的目录，存入解压的文件）
     * @param decompressSuffs 要提取文件的后缀名
     * @return
     */
    public static void decompressToDirectory(File compressFile, String baseDirectory, List<String> decompressSuffs) throws Exception
    {

        InputStream in = null;
        FileOutputStream out = null;
        ZipFile zip = null;
        try
        {
            // 验证压缩文件
            boolean isFile = compressFile.isFile();
            if (!isFile)
            {
                logger.error(String.format("compressFile非文件格式！", compressFile.getName()));
                return;
            }
            String compressFileSuff = FileUtil.getSuffix(compressFile.getName()).toLowerCase();
            if (!compressFileSuff.equals("zip"))
            {
                logger.error(String.format("[%s]文件非zip类型的压缩文件！", compressFile.getName()));
                return;
            }
            // 解压缩文件(zip)
            zip = new ZipFile(new File(compressFile.getAbsolutePath()), Charset.forName("GBK"));// 解决中文文件夹乱码
            for (Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements();)
            {
                ZipEntry entry = entries.nextElement();
                String zipEntryName = entry.getName();
                // 过滤非指定后缀文件
                String suff = FileUtil.getSuffix(zipEntryName).toLowerCase();
                if (decompressSuffs != null && decompressSuffs.size() > 0)
                {
                    if (decompressSuffs.stream().filter(s -> s.equals(suff)).collect(Collectors.toList()).size() <= 0)
                    {
                        continue;
                    }
                }
                // 创建解压目录(如果复制的代码，这里会报错，没有StrUtil，这里就是创建了一个目录来存储提取的文件，你可以换其他方式来创建目录)
                File group = new File(baseDirectory);
                if (!group.exists())
                {
                    group.mkdirs();
                }
                // 解压文件到目录
                String outPath = (baseDirectory + File.separator + zipEntryName).replaceAll("\\*", "/");
                in = zip.getInputStream(entry);
                out = new FileOutputStream(outPath);
                byte[] buf1 = new byte[1024];
                int len;
                while ((len = in.read(buf1)) > 0)
                {
                    out.write(buf1, 0, len);
                }
                in.close();
                out.close();
            }
        }
        catch (Exception e)
        {
            logger.error(e.getMessage());
        }finally {
            if(in != null) {
                IOUtils.closeQuietly(in);
            }
            if(out != null) {
                IOUtils.closeQuietly(out);
            }
            if(zip != null) {
                IOUtils.closeQuietly(zip);
            }
        }
        // 删除临时zip文件
        logger.info("开始删除{}临时文件过程====>>>",compressFile.getAbsolutePath());
        del(compressFile.getAbsolutePath());
        logger.info("结束删除{}临时文件过程====>>>",compressFile.getAbsolutePath());
    }

}
